/*
 *  Copyright (c) 1998, 1999, 2000 Mike D. Schiffman <mike@infonexus.com>
 *  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/**
 * sr_protocol.h
 *
 */

#ifndef SR_PROTOCOL_H
#define SR_PROTOCOL_H

#ifdef _LINUX_
#include <stdint.h>
#endif /* _LINUX_ */

#include <sys/types.h>
#include <arpa/inet.h>

#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif

#define IP_HDR_LEN 5
#define IP_ICMP_PROTOCOL 1
#define IP_VERSION 4
#define IP_DEFAULT_TOS 0
#define IP_NON_FRAG_ID 0
#define IP_ICMP_LEN 38

/* FIXME
 * ohh how lame .. how very, very lame... how can I ever go out in public
 * again?! /mc
 */
#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN 1
#endif
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN 2
#endif
#ifdef _CYGWIN_
#ifndef __BYTE_ORDER
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#endif
#ifdef _LINUX_
#ifndef __BYTE_ORDER
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#endif
#ifdef _SOLARIS_
#ifndef __BYTE_ORDER
#define __BYTE_ORDER __BIG_ENDIAN
#endif
#endif
#ifdef _DARWIN_
#ifndef __BYTE_ORDER
#define __BYTE_ORDER __BIG_ENDIAN
#endif
#endif

/*
 * Structure of an internet header, naked of options.
 */
struct ip
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ip_hl:4;		/* header length */
    unsigned int ip_v:4;		/* version */
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int ip_v:4;		/* version */
    unsigned int ip_hl:4;		/* header length */
#else
#error "Byte ordering not specified "
#endif
    uint8_t ip_tos;			/* type of service */
    uint16_t ip_len;			/* total length */
    uint16_t ip_id;			/* identification */
    uint16_t ip_off;			/* fragment offset field */
#define	IP_RF 0x8000			/* reserved fragment flag */
#define	IP_DF 0x4000			/* dont fragment flag */
#define	IP_MF 0x2000			/* more fragments flag */
#define	IP_OFFMASK 0x1fff		/* mask for fragmenting bits */
    uint8_t ip_ttl;			/* time to live */
    uint8_t ip_p;			/* protocol */
    uint16_t ip_sum;			/* checksum */
    struct in_addr ip_src, ip_dst;	/* source and dest address */
  } __attribute__ ((packed)) ;

/*
 *  Ethernet packet header prototype.  Too many O/S's define this differently.
 *  Easy enough to solve that and define it here.
 */
struct sr_ethernet_hdr
{
#ifndef ETHER_ADDR_LEN
#define ETHER_ADDR_LEN 6
#endif
    uint8_t  ether_dhost[ETHER_ADDR_LEN];    /* destination ethernet address */
    uint8_t  ether_shost[ETHER_ADDR_LEN];    /* source ethernet address */
    uint16_t ether_type;                     /* packet type ID */
} __attribute__ ((packed)) ;

#ifndef ETHER_HDR_LEN
#define ETHER_HDR_LEN 14
#endif

#ifndef ARP_HDR_LEN
#define ARP_HDR_LEN 46
#endif

#ifndef IPHDR_ETHER
#define IPHDR_ETHER    0
#endif

#ifndef ARPHDR_ETHER
#define ARPHDR_ETHER    1
#endif

#ifndef IPPROTO_ICMP
#define IPPROTO_ICMP            0x0001  /* ICMP protocol */
#endif

#ifndef IPPROTO_TCP
#define IPPROTO_TCP             0x0006  /* TCP protocol */
#endif

#ifndef IPPROTO_UDP
#define IPPROTO_UDP             0x0011 /* UDP protocol */
#endif

#ifndef ETHERTYPE_IP
#define ETHERTYPE_IP            0x0800  /* IP protocol */
#endif

#ifndef ETHERTYPE_ARP
#define ETHERTYPE_ARP           0x0806  /* ARP */
#endif

#define ARP_REQUEST 1
#define ARP_REPLY   2

struct sr_arphdr
{
    unsigned short  ar_hrd;             /* format of hardware address   */
    unsigned short  ar_pro;             /* format of protocol address   */
    unsigned char   ar_hln;             /* length of hardware address   */
    unsigned char   ar_pln;             /* length of protocol address   */
    unsigned short  ar_op;              /* ARP opcode (command)         */
    unsigned char   ar_sha[ETHER_ADDR_LEN];   /* sender hardware address      */
    uint32_t        ar_sip;             /* sender IP address            */
    unsigned char   ar_tha[ETHER_ADDR_LEN];   /* target hardware address      */
    uint32_t        ar_tip;             /* target IP address            */
} __attribute__ ((packed)) ;

struct sr_icmphdr
{
	uint8_t icmp_type; 					/* type of icmp message */
	uint8_t icmp_code; 					/* code of icmp message */
    uint16_t icmp_sum;					/* icmp checksum */
    uint16_t icmp_id;					/* icmp ID */
    uint16_t icmp_seq;					/* icmp sequence number */
    uint16_t icmp_ohc;					/* icmp outbound count */
    uint16_t icmp_rhc;					/* icmp return count */
} __attribute__ ((packed));

#define ICMP_TYPE_ECHO_REPLY 0
#define ICMP_TYPE_DEST_UNREACHABLE 3
#define ICMP_TYPE_ECHO_REQUEST 8
#define ICMP_TYPE_TIME_EXCEEDED 11
#define ICMP_TYPE_TRACE_ROUTE 30
#define ICMP_CODE_ECHO_REPLY 0

#define ICMP_CODE_DEST_HOST_UNREACHABLE 1
#define ICMP_CODE_DEST_PORT_UNREACHABLE 2
#define ICMP_CODE_DEST_PROTOCOL_UNREACHABLE 3
#define ICMP_CODE_DEST_HOST_UNKNOWN 7
#define ICMP_CODE_TRACE_CODE 0

#define ICMP_CODE_ECHO_REQUES 0

#define ICMP_CODE_TTL_EXPIRED 0



/*
 * Structure of an transport control protocol, header, naked of options.
 */
struct tcp
  {
	uint16_t tcp_source, tcp_dest;		/* tcp source and destination addresses */
	uint32_t tcp_seq_num; 					/* tcp sequence number */
	uint32_t tcp_ack_num; 					/* tcp acknowledgement number */
	unsigned int tcp_off:4;				/* tcp offset */
	unsigned int tcp_res:4;				/* tcp reserved */
	unsigned int tcp_cwr:1;				/* tcp CWR */
	unsigned int tcp_ece:1;				/* tcp ECE */
	unsigned int tcp_urg:1;				/* tcp URG */
	unsigned int tcp_ack:1;				/* tcp ACK */
	unsigned int tcp_psh:1;				/* tcp PSH */
	unsigned int tcp_rst:1;				/* tcp RST */
	unsigned int tcp_syn:1;				/* tcp SYN */
	unsigned int tcp_fin:1;				/* tcp FIN */
	uint16_t tcp_window;				/* tcp window size */
	uint16_t tcp_sum;					/* tcp checksum */
	uint16_t tcp_urgent;				/* tcp urgent pointer */
  } __attribute__ ((packed)) ;

  struct sr_udphdr
  {
  	uint16_t udp_src_port;				/* udp source port */
  	uint16_t udp_dest_port;				/* udp destination port */
  	uint16_t udp_len;					/* udp length */
  	uint16_t udp_sum;					/* udp checksum */
  } __attribute__ ((packed));

#endif /* -- SR_PROTOCOL_H -- */
